import logging
import json
import os
from typing import Dict, List, Optional, Callable, Any
import threading
import time

logger = logging.getLogger(__name__)

# 全局场景管理器实例（稍后定义）
_scene_manager_instance = None
_scene_manager_lock = threading.Lock()


class Scene:
    """场景类，定义场景的基本属性和方法"""
    
    def __init__(self, scene_id: str, name: str, description: str = ""):
        """
        初始化场景
        
        Args:
            scene_id: 场景唯一标识符
            name: 场景名称
            description: 场景描述
        """
        self.scene_id = scene_id
        self.name = name
        self.description = description
        self.config = {}
        self.activation_rules = []  # 场景激活规则
        self.created_at = time.time()
        self.updated_at = time.time()
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            "scene_id": self.scene_id,
            "name": self.name,
            "description": self.description,
            "config": self.config,
            "activation_rules": self.activation_rules,
            "created_at": self.created_at,
            "updated_at": self.updated_at
        }
    
    def update(self, **kwargs):
        """更新场景属性"""
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)
        self.updated_at = time.time()


class SceneManager:
    """场景管理器，负责管理多个场景的创建、切换和状态监控"""
    
    def __init__(self, config_path: Optional[str] = None):
        """
        初始化场景管理器
        
        Args:
            config_path: 场景配置文件路径
        """
        self.scenes: Dict[str, Scene] = {}
        self.active_scene_id: Optional[str] = None
        self.config_path = config_path
        self.lock = threading.RLock()  # 使用可重入锁保证线程安全
        self.on_scene_changed_callbacks: List[Callable] = []
        
        # 场景切换统计
        self.stats = {
            'total_switches': 0,
            'last_switch_time': 0,
            'scene_activation_counts': {},
            'current_activation_duration': 0,
            'last_activation_time': 0
        }
        
        # 尝试从配置文件加载场景
        if config_path and os.path.exists(config_path):
            self._load_scenes_from_file()
    
    def create_scene(self, scene_id: str, name: str, description: str = "") -> Scene:
        """
        创建新场景
        
        Args:
            scene_id: 场景唯一标识符
            name: 场景名称
            description: 场景描述
            
        Returns:
            创建的场景对象
        """
        with self.lock:
            if scene_id in self.scenes:
                logger.warning(f"场景ID已存在: {scene_id}")
                return self.scenes[scene_id]
            
            scene = Scene(scene_id, name, description)
            self.scenes[scene_id] = scene
            logger.info(f"创建新场景: {scene_id} - {name}")
            
            # 保存到配置文件
            if self.config_path:
                self._save_scenes_to_file()
            
            return scene
    
    def get_scene(self, scene_id: str) -> Optional[Scene]:
        """
        获取场景对象
        
        Args:
            scene_id: 场景ID
            
        Returns:
            场景对象，如果不存在返回None
        """
        with self.lock:
            return self.scenes.get(scene_id)
    
    def list_scenes(self) -> List[Scene]:
        """
        获取所有场景列表
        
        Returns:
            场景对象列表
        """
        with self.lock:
            return list(self.scenes.values())
    
    def update_scene(self, scene_id: str, **kwargs) -> Optional[Scene]:
        """
        更新场景属性
        
        Args:
            scene_id: 场景ID
            **kwargs: 要更新的属性
            
        Returns:
            更新后的场景对象，如果不存在返回None
        """
        with self.lock:
            if scene_id not in self.scenes:
                logger.warning(f"场景不存在: {scene_id}")
                return None
            
            scene = self.scenes[scene_id]
            scene.update(**kwargs)
            logger.info(f"更新场景: {scene_id}")
            
            # 保存到配置文件
            if self.config_path:
                self._save_scenes_to_file()
            
            return scene
    
    def delete_scene(self, scene_id: str) -> bool:
        """
        删除场景
        
        Args:
            scene_id: 场景ID
            
        Returns:
            是否删除成功
        """
        with self.lock:
            if scene_id not in self.scenes:
                logger.warning(f"场景不存在: {scene_id}")
                return False
            
            # 如果是当前活动场景，先切换到None
            if self.active_scene_id == scene_id:
                self.active_scene_id = None
                self._notify_scene_changed(None)
            
            del self.scenes[scene_id]
            logger.info(f"删除场景: {scene_id}")
            
            # 保存到配置文件
            if self.config_path:
                self._save_scenes_to_file()
            
            return True
    
    def switch_to_scene(self, scene_id: Optional[str]) -> bool:
        """
        切换到指定场景
        
        Args:
            scene_id: 要切换到的场景ID，None表示无活动场景
            
        Returns:
            是否切换成功
        """
        with self.lock:
            # 检查场景是否存在
            if scene_id is not None and scene_id not in self.scenes:
                logger.warning(f"场景不存在: {scene_id}")
                return False
            
            # 如果已经是当前场景，不需要切换
            if self.active_scene_id == scene_id:
                logger.debug(f"已经在场景: {scene_id}")
                return True
            
            old_scene_id = self.active_scene_id
            self.active_scene_id = scene_id
            
            # 更新统计信息
            self.stats['total_switches'] += 1
            self.stats['last_switch_time'] = time.time()
            
            if scene_id:
                self.stats['scene_activation_counts'][scene_id] = \
                    self.stats['scene_activation_counts'].get(scene_id, 0) + 1
                self.stats['last_activation_time'] = time.time()
                self.stats['current_activation_duration'] = 0
            
            logger.info(f"场景切换: {old_scene_id} -> {scene_id}")
            
            # 通知场景变化
            self._notify_scene_changed(scene_id)
            
            return True
    
    def get_active_scene(self) -> Optional[Scene]:
        """
        获取当前活动场景
        
        Returns:
            当前活动场景对象，如果没有活动场景返回None
        """
        with self.lock:
            if not self.active_scene_id:
                return None
            return self.scenes.get(self.active_scene_id)
    
    def register_scene_changed_callback(self, callback: Callable):
        """
        注册场景变化回调
        
        Args:
            callback: 当场景变化时调用的函数，接收新场景ID作为参数
        """
        with self.lock:
            if callback not in self.on_scene_changed_callbacks:
                self.on_scene_changed_callbacks.append(callback)
    
    def unregister_scene_changed_callback(self, callback: Callable):
        """
        取消注册场景变化回调
        
        Args:
            callback: 要取消注册的回调函数
        """
        with self.lock:
            if callback in self.on_scene_changed_callbacks:
                self.on_scene_changed_callbacks.remove(callback)
    
    def update_statistics(self):
        """
        更新场景统计信息，主要是当前场景的激活时长
        """
        with self.lock:
            if self.active_scene_id and self.stats['last_activation_time'] > 0:
                self.stats['current_activation_duration'] = \
                    time.time() - self.stats['last_activation_time']
    
    def analyze_scene(self, frame_data: Dict[str, Any]) -> Optional[str]:
        """
        分析帧数据，根据规则确定应该切换到哪个场景
        
        Args:
            frame_data: 帧数据，包含检测结果等信息
            
        Returns:
            推荐的场景ID，如果没有匹配的规则返回None
        """
        # 这里可以实现基于检测结果的智能场景切换逻辑
        # 目前返回None，表示使用手动切换
        return None
    
    def _notify_scene_changed(self, new_scene_id: Optional[str]):
        """
        通知所有注册的回调函数场景已变化
        
        Args:
            new_scene_id: 新的场景ID
        """
        for callback in self.on_scene_changed_callbacks:
            try:
                callback(new_scene_id)
            except Exception as e:
                logger.error(f"场景变化回调错误: {str(e)}")
    
    def _load_scenes_from_file(self):
        """从配置文件加载场景"""
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
                # 加载场景列表
                for scene_data in data.get('scenes', []):
                    scene = Scene(
                        scene_id=scene_data['scene_id'],
                        name=scene_data['name'],
                        description=scene_data.get('description', '')
                    )
                    scene.config = scene_data.get('config', {})
                    scene.activation_rules = scene_data.get('activation_rules', [])
                    scene.created_at = scene_data.get('created_at', time.time())
                    scene.updated_at = scene_data.get('updated_at', time.time())
                    self.scenes[scene.scene_id] = scene
                
                # 恢复上次活动场景
                self.active_scene_id = data.get('active_scene_id')
                
                logger.info(f"从配置文件加载了 {len(self.scenes)} 个场景")
        except Exception as e:
            logger.error(f"从配置文件加载场景失败: {str(e)}")
    
    def _save_scenes_to_file(self):
        """保存场景到配置文件"""
        try:
            data = {
                'scenes': [scene.to_dict() for scene in self.scenes.values()],
                'active_scene_id': self.active_scene_id,
                'last_updated': time.time()
            }
            
            # 确保目录存在
            os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
            
            with open(self.config_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
                
            logger.debug(f"已保存 {len(self.scenes)} 个场景到配置文件")
        except Exception as e:
            logger.error(f"保存场景到配置文件失败: {str(e)}")
    
    def close(self):
        """清理资源"""
        # 保存最后状态
        if self.config_path:
            self._save_scenes_to_file()
        
        # 清空回调
        self.on_scene_changed_callbacks.clear()
        
        # 清除全局实例
        global _scene_manager_instance
        with _scene_manager_lock:
            _scene_manager_instance = None
            
        logger.info("场景管理器已关闭")


def get_scene_manager(config_path: Optional[str] = None) -> SceneManager:
    """
    获取场景管理器实例（单例模式）
    
    Args:
        config_path: 场景配置文件路径
        
    Returns:
        场景管理器实例
    """
    global _scene_manager_instance
    with _scene_manager_lock:
        if _scene_manager_instance is None:
            _scene_manager_instance = SceneManager(config_path)
            logger.info("创建了场景管理器实例")
        return _scene_manager_instance